package com.wrapp.floatlabelededittext;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.app.Context;

/**
 * 浮动TextField
 *
 * @since 2021-08-04
 */
public class FloatLabeledEditText extends StackLayout {
    private static final int DEFAULT_PADDING_LEFT = 2;

    private Text mHintTextView;
    private TextField mEditText;
    private ShapeElement getFocusElement = new ShapeElement();
    private ShapeElement loseFocusElement = new ShapeElement();

    private Context mContext;

    /**
     * 构造方法
     *
     * @param context
     */
    public FloatLabeledEditText(Context context) {
        super(context);
        mContext = context;
    }

    /**
     * 构造方法
     *
     * @param context
     * @param attrSet
     */
    public FloatLabeledEditText(Context context, AttrSet attrSet) {
        super(context, attrSet);
        mContext = context;
        setAttributes(attrSet);
    }

    /**
     * 构造方法
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public FloatLabeledEditText(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        mContext = context;
        setAttributes(attrSet);
    }

    private void setAttributes(AttrSet attrSet) {
        mHintTextView = new Text(mContext);
        mHintTextView.setTextSize(39);
        TypedArray a = new TypedArray(attrSet);

        final int defaultPadding = 5;
        final int padding = a.getDimensionValue("fletPadding", 0);
        final int paddingLeft = a.getDimensionValue("fletPaddingLeft", defaultPadding);
        final int paddingTop = a.getDimensionValue("fletPaddingTop", 0);
        final int paddingRight = a.getDimensionValue("fletPaddingRight", 0);
        final int paddingBottom = a.getDimensionValue("fletPaddingBottom", 0);
        final boolean isBold = a.getBoolean("fletIsBold", false);
        final boolean isIncline = a.getBoolean("fletisIncline", false);
        Element background = a.getElement("fletBackground");

        if (padding != 0) {
            mHintTextView.setPadding(padding, padding, padding, padding);
        } else {
            mHintTextView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
        }

        if (background != null) {
            setHintBackground(background);
        }

        if (isBold) {
            mHintTextView.setFont(Font.DEFAULT_BOLD);
        }

        if (isIncline) {
            mHintTextView.setFont(Font.SANS_SERIF);
        }

        mHintTextView.setTextColor(a.getColor("fletTextAppearance", Color.getIntColor("#7F7F7F")));

        mHintTextView.setVisibility(Component.INVISIBLE);
        mHintTextView.setAlpha(0);

        getFocusElement.setRgbColor(new RgbColor(66, 171, 160));
        loseFocusElement.setRgbColor(new RgbColor(131, 131, 131));

        addComponent(mHintTextView, LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_CONTENT);
    }

    @SuppressLint("NewApi")
    private void setHintBackground(Element background) {
        mHintTextView.setBackground(background);
    }

    @Override
    public final void addComponent(Component child) {
        if (child instanceof TextField) {
            if (mEditText != null) {
                throw new IllegalArgumentException("Can only have one Edittext subview");
            }

            LayoutConfig lp = new LayoutConfig();
            lp.width = DependentLayout.LayoutConfig.MATCH_PARENT;
            int i = mHintTextView.getTextSize() + mHintTextView.getPaddingBottom() + mHintTextView.getPaddingTop();
            lp.setMarginTop(i);
            child.setLayoutConfig(lp);
            setTextField((TextField)child);
        }
        super.addComponent(child);
    }

    private void setTextField(TextField editText) {
        mEditText = editText;

        mEditText.addTextObserver(new Text.TextObserver() {
            @Override
            public void onTextUpdated(String s, int i, int i1, int i2) {
                if (!s.equals("\n")) {
                    setShowHint(!s.isEmpty());
                }
            }
        });

        mEditText.setFocusChangedListener(new FocusChangedListener() {
            @Override
            public void onFocusChange(Component component, boolean gotFocus) {
                onFocusChanged(gotFocus);
            }
        });

        mHintTextView.setText(mEditText.getHint());

        if (!mEditText.getText().isEmpty()) {
            mHintTextView.setVisibility(VISIBLE);
        }
    }

    private void onFocusChanged(boolean gotFocus) {
        if (gotFocus) {
            mEditText.setBasement(getFocusElement);
        } else {
            mEditText.setBasement(loseFocusElement);
        }
        if (gotFocus && mHintTextView.getVisibility() == VISIBLE) {
            mHintTextView.createAnimatorProperty().alphaFrom(0.33f).alpha(1).start();
        } else if (mHintTextView.getVisibility() == VISIBLE) {
            mHintTextView.createAnimatorProperty().alphaFrom(1f).alpha(0.33f).start();
        }
    }

    private void setShowHint(boolean show) {
        AnimatorGroup animation = new AnimatorGroup();
        AnimatorGroup.Builder build = animation.build();

        if ((mHintTextView.getVisibility() == VISIBLE) && !show) {
            AnimatorProperty move = mHintTextView.createAnimatorProperty()
                    .moveFromY(0).moveToY(mHintTextView.getHeight() / 8);
            AnimatorProperty fade = mHintTextView.createAnimatorProperty().alphaFrom(1).alpha(0);
            build.addAnimators(move, fade);
        } else if ((mHintTextView.getVisibility() != VISIBLE) && show) {
            AnimatorProperty move = mHintTextView.createAnimatorProperty()
                    .moveFromY(mHintTextView.getHeight() / 8).moveToY(0);
            AnimatorProperty fade;
            if (mEditText.isFocused()) {
                fade = mHintTextView.createAnimatorProperty().alphaFrom(0).alpha(1);
            } else {
                fade = mHintTextView.createAnimatorProperty().alphaFrom(0).alpha(0.33f);
            }
            build.addAnimators(move, fade);
        }

        if (animation != null) {
            animation.setStateChangedListener(new Animator.StateChangedListener() {
                @Override
                public void onStart(Animator animator) {
                    mHintTextView.setVisibility(VISIBLE);
                }

                @Override
                public void onStop(Animator animator) {
                }

                @Override
                public void onCancel(Animator animator) {
                }

                @Override
                public void onEnd(Animator animator) {
                    mHintTextView.setVisibility(show ? VISIBLE : INVISIBLE);
                    if (show) {
                        mHintTextView.createAnimatorProperty().alpha(1).start();
                    } else {
                        mHintTextView.createAnimatorProperty().alpha(0).start();
                    }
                }

                @Override
                public void onPause(Animator animator) {
                }

                @Override
                public void onResume(Animator animator) {
                }
            });
            animation.start();
        }
    }

    /**
     * 获取内部TextField
     *
     * @return TextField
     */
    public TextField getEditText() {
        return mEditText;
    }

    /**
     * 设置Hint
     *
     * @param hint
     */
    public void setHint(String hint) {
        mEditText.setHint(hint);
        mHintTextView.setText(hint);
    }

    /**
     * 获取Hint
     *
     * @return  CharSequence
     */
    public CharSequence getHint() {
        return mHintTextView.getHint();
    }

    /**
     * 设置浮动文字大小
     *
     * @param size
     */
    public void setHintTextSize(int size) {
        mHintTextView.setTextSize(size);
    }

    /**
     * 设置子TextField获取到焦点时的下方Basement颜色
     *
     * @param rgbColor
     */
    public void setGetFocusElement(RgbColor rgbColor) {
        getFocusElement.setRgbColor(rgbColor);
    }

    /**
     * 设置子TextField失去焦点后下方Basement颜色
     *
     * @param rgbColor
     */
    public void setLoseFocusElement(RgbColor rgbColor) {
        loseFocusElement.setRgbColor(rgbColor);
    }
}